package com.zhongying.jf.util;

import com.zhongying.jf.exception.ZhongyingiException;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author 李佳
 * @Description FTP工具类
 * @Email lijia@chinazyjr.com
 */
public class FtpUtil {

    private static final Logger LOGGER = LoggerFactory.getLogger(FtpUtil.class);

    /**
     * Description: 向FTP服务器上传文件
     * @param host FTP服务器hostname
     * @param port FTP服务器端口
     * @param username FTP登录账号
     * @param password FTP登录密码
     * @param basePath FTP服务器基础目录
     * @param filePath FTP服务器文件存放路径。例如分日期存放：/2015/01/01。文件的路径为basePath+filePath
     * @param filename 上传到FTP服务器上的文件名
     * @param input 输入流
     * @return 成功返回true，否则返回false
     */
    public static boolean uploadFile(String host, int port, String username, String password, String basePath,
                                     String filePath, String filename, InputStream input) {
        LOGGER.info("上传文件开始:host:{},port:{},username:{},password:{},basePath:{},filePath:{},filename:{},input:{}",
                host,port,username,password,basePath,filePath,filename,input);
        boolean result = false;
        FTPClient ftp = new FTPClient();
        try {
            int reply;
            // 连接FTP服务器
            ftp.connect(host, port);
            // 如果采用默认端口，可以使用ftp.connect(host)的方式直接连接FTP服务器
            // 登录
            ftp.login(username, password);
            reply = ftp.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                LOGGER.info("登录失败-->"+username+"-->"+password);
                ftp.disconnect();
                return result;
            }else {
                LOGGER.info("登录成功:"+ftp.getReplyCode()+"--->"+ftp.getReplyString());
            }
            //切换到上传目录
            if (!ftp.changeWorkingDirectory(basePath+filePath)) {
                //如果目录不存在创建目录
                /*FTP服务器不能创建多层目录，也就是FTP连接后一次只能创建一个文件夹，创建失败后返回False*/
                String[] dirs = filePath.split("/");
                String tempPath = basePath;
                ftp.changeWorkingDirectory(tempPath);
                for (String dir : dirs) {
                    if (null == dir || "".equals(dir))
                    {
                        continue;
                    }
                    tempPath = dir;
                    if (!ftp.changeWorkingDirectory(tempPath)) {
                        if (!ftp.makeDirectory(tempPath)) {
                            return result;
                        } else {
                            ftp.changeWorkingDirectory(tempPath);
                        }
                    }
                }
            }else {
                LOGGER.info("文件上传的地址是:"+basePath+filePath);
            }
            //设置上传文件的类型为二进制类型
            ftp.setFileType(FTP.BINARY_FILE_TYPE);
            //上传文件
            if (!ftp.storeFile(filename, input)) {
                LOGGER.info(filename+"文件上传失败:"+ftp.getReplyCode()+"--->"+ftp.getReplyString());
                return result;
            }
            input.close();
            ftp.logout();
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (ftp.isConnected()) {
                try {
                    ftp.disconnect();
                } catch (Exception ioe) {
                }
            }
        }
        return result;
    }

    /**
     * Description: 从FTP服务器下载文件
     * @param host FTP服务器hostname
     * @param port FTP服务器端口
     * @param username FTP登录账号
     * @param password FTP登录密码
     * @param remotePath FTP服务器上的相对路径
     * @param fileName 要下载的文件名
     * @param localPath 下载后保存到本地的路径
     * @return
     */
    public static boolean downloadFile(String host, int port, String username, String password, String remotePath,
                                       String fileName, String localPath) {
        boolean result = false;
        FTPClient ftp = new FTPClient();
        try {
            int reply;
            ftp.connect(host, port);
            // 如果采用默认端口，可以使用ftp.connect(host)的方式直接连接FTP服务器
            // 登录
            ftp.login(username, password);
            reply = ftp.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                ftp.disconnect();
                return result;
            }
            // 转移到FTP服务器目录
            ftp.changeWorkingDirectory(remotePath);
            FTPFile[] fs = ftp.listFiles();
            for (FTPFile ff : fs) {
                if (ff.getName().equals(fileName)) {
                    File localFile = new File(localPath + "/" + ff.getName());

                    OutputStream is = new FileOutputStream(localFile);
                    ftp.retrieveFile(ff.getName(), is);
                    is.close();
                }
            }

            ftp.logout();
            result = true;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (ftp.isConnected()) {
                try {
                    ftp.disconnect();
                } catch (IOException ioe) {
                }
            }
        }
        return result;
    }

    /**
     * Description: 从FTP服务器下载文件
     * @param host FTP服务器hostname
     * @param port FTP服务器端口
     * @param username FTP登录账号
     * @param password FTP登录密码
     * @param remotePath FTP服务器上的相对路径
     * @return
     */
    public static byte[] downloadFile(String host, int port, String username, String password, String remotePath) {
        FTPClient ftp = new FTPClient();
        try {
            int reply;
            ftp.connect(host, port);
            // 如果采用默认端口，可以使用ftp.connect(host)的方式直接连接FTP服务器
            // 登录
            ftp.login(username, password);
            reply = ftp.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                ftp.disconnect();
                return null;
            }
            // 转移到FTP服务器目录
            ByteArrayOutputStream is = new ByteArrayOutputStream();
            ftp.retrieveFile(remotePath, is);
            is.close();
            ftp.logout();
            return is.toByteArray();

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (ftp.isConnected()) {
                try {
                    ftp.disconnect();
                } catch (IOException ioe) {
                }
            }
        }
        return null;
    }

    /**
     * 下载ftp文件夹下所有文件
     * @param host
     * @param port
     * @param username
     * @param password
     * @param remotePath
     * @return Map("fileName":文件名(带后缀),"fileByte":文件字节流)
     */
    public static List<Map> downLoadInDocument(String host, int port, String username, String password, String remotePath) throws ZhongyingiException {
        List<Map> files = new ArrayList<>();
        FTPClient ftp = new FTPClient();
        try {
            int reply;
            ftp.connect(host, port);
            // 如果采用默认端口，可以使用ftp.connect(host)的方式直接连接FTP服务器
            // 登录
            ftp.login(username, password);
            reply = ftp.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                ftp.disconnect();

            }else {
                LOGGER.info("{}登录{}{}成功",username,host,port);
            }
            // 转移到FTP服务器目录
            ftp.changeWorkingDirectory(remotePath);
            // 下载文件
            ftp.setBufferSize(1024);
            ftp.setControlEncoding("UTF-8");
            ftp.setFileType(FTP.BINARY_FILE_TYPE);
            FTPFile[] fs = ftp.listFiles();
            for (FTPFile ff : fs) {
                if (ff.isDirectory()){
                    continue;
                }
                String remoteAbsoluteFile = ff.getName();
                //文件转码
                remoteAbsoluteFile = new String(remoteAbsoluteFile.getBytes("UTF-8"), "ISO-8859-1");
                InputStream in = ftp.retrieveFileStream(remoteAbsoluteFile);
                byte[] bytes = input2byte(in);
                /*

                 * You must close the InputStream when you

                 * finish reading from it. The InputStream itself will take care of

                 * closing the parent data connection socket upon being closed. To

                 * finalize the file transfer you must call

                 * {@link #completePendingCommand completePendingCommand } and

                 * check its return value to verify success.

                 */
                in.close();
                ftp.completePendingCommand();
                System.out.println(remotePath+"下的:"+ff.getName()+",下载成功"+":"+bytes.length);
                LOGGER.info(remotePath+"下的:{},下载成功:{}",ff.getName(),bytes.length);
                Map map = new HashMap(16);
                map.put("fileName",ff.getName());
                map.put("fileByte",bytes);
                files.add(map);
            }

            ftp.logout();

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (ftp.isConnected()) {
                try {
                    ftp.disconnect();
                } catch (IOException ioe) {
                }
            }
        }
        return files;
    }

    /**
     * 根据byte数组，生成文件
     * @param bfile 文件数组
     * @param filePath 文件存放路径
     * @param fileName 文件名称
     */
    public static void byte2File(byte[] bfile,String filePath,String fileName){
        BufferedOutputStream bos=null;
        FileOutputStream fos=null;
        File file=null;
        try{

            File dir=new File(filePath);
            //判断文件目录是否存在
            if(!dir.exists() && !dir.isDirectory()){
                dir.mkdirs();
            }
            file=new File(filePath+fileName);
            fos=new FileOutputStream(file);
            bos=new BufferedOutputStream(fos);
            bos.write(bfile);

        }
        catch(Exception e){
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
        finally{
            try{
                if(bos != null){
                    bos.close();
                }
                if(fos != null){
                    fos.close();
                }
            }
            catch(Exception e){
                System.out.println(e.getMessage());
                e.printStackTrace();
            }
        }
    }


    /**
     * 文件输入流转字节流
     * @param inStream
     * @return
     * @throws IOException
     */
    public static byte[] input2byte(InputStream inStream) throws IOException {
        ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
        byte[] buff = new byte[100];
        int rc = 0;
        while ((rc = inStream.read(buff, 0, 100)) > 0)
        {
            swapStream.write(buff, 0, rc);
        }
        byte[] in2b = swapStream.toByteArray();

        swapStream.close();

        return in2b;
    }

    public static void main(String[] args) {
        List<Map> bytes = FtpUtil.downLoadInDocument("192.168.50.56",21,"document","document","/scd/lijiatest/");
        for (Map m : bytes){
            FtpUtil.byte2File((byte[]) m.get("fileByte"),"G:\\test\\",m.get("fileName").toString());
        }
    }
}
